#include <gtest/gtest.h>
#include "viml/instruction.h"
#include "viml/value.h"

TEST(InstructionTest, BasicInstructionCreation) {
    // 测试ABC格式指令
    viml::Instruction inst(viml::OpCode::ADD, 1, 2, 3);
    
    EXPECT_EQ(inst.opcode(), viml::OpCode::ADD);
    EXPECT_EQ(inst.a(), 1);
    EXPECT_EQ(inst.b(), 2);
    EXPECT_EQ(inst.c(), 3);
}

TEST(InstructionTest, ABxFormatInstruction) {
    // 测试ABx格式指令
    viml::Instruction inst(viml::OpCode::LOAD_CONST, static_cast<uint8_t>(5), static_cast<uint16_t>(1000));
    
    EXPECT_EQ(inst.opcode(), viml::OpCode::LOAD_CONST);
    EXPECT_EQ(inst.a(), 5);
    EXPECT_EQ(inst.bx(), 1000);
}

TEST(InstructionTest, InstructionToString) {
    viml::Instruction add_inst(viml::OpCode::ADD, 0, 1, 2);
    std::string str = add_inst.to_string();
    
    EXPECT_TRUE(str.find("ADD") != std::string::npos);
    EXPECT_TRUE(str.find("R0") != std::string::npos);
    EXPECT_TRUE(str.find("R1") != std::string::npos);
    EXPECT_TRUE(str.find("R2") != std::string::npos);
}

TEST(BytecodeTest, ConstantPool) {
    viml::Bytecode bytecode("test");
    
    // 添加常量
    auto idx1 = bytecode.add_constant(viml::Value::make_number(42.0));
    auto idx2 = bytecode.add_constant(viml::Value::string("hello"));
    auto idx3 = bytecode.add_constant(viml::Value::make_number(42.0)); // 重复常量
    
    EXPECT_EQ(idx1, idx3); // 重复常量应该返回相同索引
    EXPECT_NE(idx1, idx2);
    
    EXPECT_TRUE(bytecode.get_constant(idx1).is_number());
    EXPECT_EQ(bytecode.get_constant(idx1).as_number(), 42.0);
    
    EXPECT_TRUE(bytecode.get_constant(idx2).is_string());
    EXPECT_EQ(bytecode.get_constant(idx2).as_string(), "hello");
}

TEST(BytecodeTest, NamePool) {
    viml::Bytecode bytecode("test");
    
    // 添加名字
    auto idx1 = bytecode.add_name("variable");
    auto idx2 = bytecode.add_name("function");
    auto idx3 = bytecode.add_name("variable"); // 重复名字
    
    EXPECT_EQ(idx1, idx3); // 重复名字应该返回相同索引
    EXPECT_NE(idx1, idx2);
    
    EXPECT_EQ(bytecode.get_name(idx1), "variable");
    EXPECT_EQ(bytecode.get_name(idx2), "function");
}

TEST(BytecodeTest, InstructionManagement) {
    viml::Bytecode bytecode("test");
    
    // 添加指令
    bytecode.add_instruction(viml::OpCode::LOAD_CONST, static_cast<uint8_t>(0), static_cast<uint16_t>(1));
    bytecode.add_instruction(viml::OpCode::ADD, static_cast<uint8_t>(1), static_cast<uint8_t>(0), static_cast<uint8_t>(0));
    bytecode.add_instruction(viml::OpCode::HALT);
    
    EXPECT_EQ(bytecode.instruction_count(), 3);
    
    auto& inst1 = bytecode.get_instruction(0);
    EXPECT_EQ(inst1.opcode(), viml::OpCode::LOAD_CONST);
    
    auto& inst2 = bytecode.get_instruction(1);
    EXPECT_EQ(inst2.opcode(), viml::OpCode::ADD);
    
    auto& inst3 = bytecode.get_instruction(2);
    EXPECT_EQ(inst3.opcode(), viml::OpCode::HALT);
}